package open.douban.hashtree;

import java.io.File;
import java.io.IOException;

import junit.framework.Assert;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import open.douban.hashtree.HashTree.Item;

/**
 * To run the test: -Xmx1024m
 */
public class HashTreeTest {
	static HashTree ht = null;
	static int max_id = HashTree.g_index[HashTree1.MAX_HEIGHT + 1] - 1;
	static String path = "temp" + System.currentTimeMillis();

	@BeforeClass
	public static void setup() throws IOException {
		ht = getHashTree(path);
	}

	@AfterClass
	public static void tearDown() {
		File f = new File(path);
		f.deleteOnExit();
	}

	public static HashTree getHashTree(String path) throws IOException {
//		return new HashTreeInArray(path);
		 return new HashTreeInMap(path);
		// return new HashTree1(path);
	}

	private int print = 1000000;

	@Test
	public void testAddItem() throws IOException {
		int cnt = max_id;
		long s = System.currentTimeMillis();
		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("add: " + i);
			ht.setItem(i, i, false);
		}
		long e = System.currentTimeMillis();
		System.out.println("add speed: " + (max_id * 1000.0 / (e - s)));

		s = System.currentTimeMillis();
		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("find: " + i);
			Item item = ht.findItem(i);
			Assert.assertEquals(item.key, i);
			Assert.assertEquals(item.hash_v, i);
		}
		e = System.currentTimeMillis();
		System.out.println("find speed: " + (max_id * 1000.0 / (e - s)));

		s = System.currentTimeMillis();
		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("remove: " + i);
			ht.removeItem(i, false);
		}
		e = System.currentTimeMillis();
		System.out.println("remove speed: " + (max_id * 1000.0 / (e - s)));

		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("find: " + i);
			Item item = ht.findItem(i);
			Assert.assertNull(item);
		}
	}

	@Test
	public void testSetItem() throws IOException {
		int cnt = max_id;
		for (int i = 1; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("set: " + i);
			ht.setItem(i, i, false);
			ht.setItem(i, i * 2, false);
		}

		for (int i = 1; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("find: " + i);
			Item item = ht.findItem(i);
			Assert.assertEquals(item.key, i);
			Assert.assertEquals(item.hash_v, i * 2);
		}

	}

	@Test
	public void testSave() throws IOException {
		long s = System.currentTimeMillis();
		int cnt = max_id;
		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("add: " + i);
			ht.setItem(i, i, false);
		}
		long e = System.currentTimeMillis();
		System.out.println("add speed: " + (max_id * 1000.0 / (e - s)));

		s = System.currentTimeMillis();
		ht.save();
		e = System.currentTimeMillis();
		System.out.println("flush speed: " + (max_id * 1000.0 / (e - s)));

		// release heap, can not load two big tree in the same time
		if (cnt > 7777777)
			ht = null;
		s = System.currentTimeMillis();
		HashTree hashtree = getHashTree(path);
		e = System.currentTimeMillis();
		System.out.println("load speed: " + (max_id * 1000.0 / (e - s)));

		if (cnt > 7777777)
			ht = hashtree;
		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("find: " + i);

			Item item = hashtree.findItem(i);
			Assert.assertEquals(item.key, i);
			Assert.assertEquals(item.hash_v, i);

			item = ht.findItem(i);
			Assert.assertEquals(item.key, i);
			Assert.assertEquals(item.hash_v, i);
		}

		for (int i = 0; i < cnt; i++) {
			if (i % print == 0)
				System.out.println("remove: " + i);
			ht.removeItem(i, false);
		}

		ht.save();

		hashtree = getHashTree(path);
		for (int i = 0; i < cnt; i++) {
			Item item = hashtree.findItem(i);
			Assert.assertNull(item);

			item = ht.findItem(i);
			Assert.assertNull(item);
		}
	}
}
